package com.google.jessewilson.codesearch.api;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;

/**
 * The programming language a code file is written in.
 *
 * @author jessewilson
 */
public class ProgrammingLanguage {

  /**
   * recognizers for popular programming languges
   */
  private static final List<ProgrammingLanguage> WITH_PATTERNS = Collections
      .unmodifiableList(Arrays.asList(
          new ProgrammingLanguage("Java", ".*[A-Z][A-Za-z0-9_]*\\.java$"),
          new ProgrammingLanguage("C", ".*\\.[ch]$"),
          new ProgrammingLanguage("C++", ".*\\.(cc|cpp)$"),
          new ProgrammingLanguage("C#", ".*\\.cs$"),
          new ProgrammingLanguage("Python", ".*\\.py$"),
          new ProgrammingLanguage("Ruby", ".*\\.rb$"),
          new ProgrammingLanguage("Perl", ".*\\.pl$"),
          new ProgrammingLanguage("Perl Module", ".*\\.pm$"),
          new ProgrammingLanguage("ML", ".*\\.ml$"),
          new ProgrammingLanguage("Shell Script", ".*\\.(sh|bat)$"),
          new ProgrammingLanguage("JavaScript", ".*\\.js$"),
          new ProgrammingLanguage("HTML", ".*\\.x?html$"),
          new ProgrammingLanguage("XML", ".*\\.xml$"),
          new ProgrammingLanguage("PHP", ".*\\.php$")
      ));
  private static final ProgrammingLanguage OTHER = new ProgrammingLanguage("Other", null);

  private final String name;

  private final Pattern filenamePattern;

  public ProgrammingLanguage(String name, String filenamePattern) {
    this.name = name;
    if (filenamePattern != null) {
      this.filenamePattern = Pattern.compile(filenamePattern);
    } else {
      this.filenamePattern = null;
    }
  }

  public String getName() {
    return name;
  }

  public String toString() {
    return name;
  }

  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    ProgrammingLanguage language = (ProgrammingLanguage) o;
    if (!name.equals(language.name)) {
      return false;
    }
    return true;
  }

  public int hashCode() {
    return name.hashCode();
  }

  public static ProgrammingLanguage fromFileName(String fileName) {
    for (ProgrammingLanguage programmingLanguage : WITH_PATTERNS) {
      if (programmingLanguage.filenamePattern != null
          && programmingLanguage.filenamePattern.matcher(fileName).matches()) {
        return programmingLanguage;
      }
    }

    String extension = getExtension(fileName);
    if (extension != null) {
      return new ProgrammingLanguage(extension + " Files", null);
    } else {
      return OTHER;
    }
  }

  /**
   * Extract the extension from the filename, such as "txt" from "foo.txt"
   */
  static String getExtension(String filename) {
    int lastDot = filename.lastIndexOf('.');
    if(lastDot != -1) {
      return filename.substring(lastDot + 1);
    } else {
      return null;
    }
  }
}
